/**
 * This class defines a number that can be spelled. 
 * Each number is split into segment of three to make it easier to spell. 
 * @author David Emole
 */
package com.spell;

import static com.spell.SpellConstants.*;

public class PartitionedNumber {
	private boolean isNegative;
	private boolean hasDecimal;
	private int[] tripleSections;
	private String[] partitionSpellOuts;
	private String decimalpart;
	private int numberOfsections;
	private String wholepart;
	
	public PartitionedNumber(String numberString){
		
		//case: negative number
		if(numberString.startsWith("-")){
			isNegative=true;
			numberString = numberString.substring(1);
		}
		
		divideNumberIntoPartitions(numberString);

		spellPartitions();
	}
	
	/**
	 * Divide the string into sections of three, starting from the back.
	 * Objective: "1234" should give ["1", "234"] 
	 */
	private void divideNumberIntoPartitions(String str){
		//case: if number has decimal point
		if(str.contains(".")){
			hasDecimal=true;
			decimalpart = str.substring(str.indexOf('.')+1);
			wholepart = str.substring(0,str.indexOf('.'));
		}
		else{
			wholepart = str;
			decimalpart = "";
		}

		//Find the number of sections to be created.
		numberOfsections = wholepart.length()/3;
		int rem = wholepart.length() % 3;
		if(rem>0)
			numberOfsections += 1;

		//Create sections
		tripleSections = new int[numberOfsections];
		partitionSpellOuts = new String[numberOfsections];

		int firstsectionsize = (rem>0) ? rem : 3;
		int beg = 0;
		int end = firstsectionsize; 
		for(int i=0;i<numberOfsections;i++){
			tripleSections[i] = Integer.parseInt(wholepart.substring(beg,end));
			beg=end;
			end+=3;
		}
	}

	private void spellPartitions(){
		for(int i = 0; i < numberOfsections; i++){
			int tripleIndex = numberOfsections - i - 1;
			partitionSpellOuts[i] = spellThreeDigits(tripleSections[i]) + (i==numberOfsections-1 ? "" : " ") + TRIPLES[tripleIndex];
		}
	}
	
	public String getSpelling(){
		StringBuilder spelling = new StringBuilder();
		
		if(isNegative)
			spelling.append(MINUS_SPELLING + " ");
		
		spelling.append(getWholeSpelling());
		
		if(!decimalpart.isEmpty()){
			spelling.append(" " + POINT_SPELLING + " ");
			spelling.append(getDecimalSpelling());
		}
		
		return spelling.toString();
	}
	
	private String getWholeSpelling(){
		StringBuilder numbuild = new StringBuilder();
		for(int i = 0; i < numberOfsections; i++){
			if(tripleSections[i]==0 && i < numberOfsections-1) 
				continue;
			
			numbuild.append(partitionSpellOuts[i]);
			
			//Seperator Logic
			if(i < numberOfsections-2 || (i == numberOfsections-2 && partitionSpellOuts[i+1].contains("and"))) 
				numbuild.append(", ");
			else if(i == numberOfsections-2 && !partitionSpellOuts[i+1].contains("and"))
				numbuild.append(" and ");
		}
		return SpellUtils.capitalizeFirstLetter(numbuild.toString());
	}
	
	private String getDecimalSpelling(){
		StringBuilder sb = new StringBuilder();
		for(int i=0, len = decimalpart.length(); i < len ; i++){
			int digit = Character.getNumericValue(decimalpart.charAt(i));
			sb.append(ZERO_THRU_19[digit]);

			if(i != len-1)
				sb.append(" ");
		}
		return sb.toString();
	}
	
	/*** This spells out a number between 0 and 999.**/
	private String spellThreeDigits(int number){
		if(number < 100)
			return spellTwoDigits(number);

		//Case: numbers 100 - 999
		char[] digits = String.valueOf(number).toCharArray();
		int hundreds = Character.getNumericValue(digits[0]);
		String strHun = ZERO_THRU_19[hundreds] + " hundred";

		int remainder = number - (hundreds * 100);
		if(remainder > 0)
			return strHun + " and " + spellTwoDigits(remainder);
		else
			return strHun;
	}
	
	/*** This spells out a number between 0 and 99. */
	private String spellTwoDigits(int number)
	{
		//Case: numbers 0 - 19
		if(number <= 19)
			return ZERO_THRU_19[number];
		
		//Case: numbers 20 - 99
		char[] digits = String.valueOf(number).toCharArray();

		int units = Character.getNumericValue(digits[1]);
		int tens = Character.getNumericValue(digits[0]);
		if(units > 0)
			return TENS[tens] + "-" + ZERO_THRU_19[units];
		else
			return TENS[tens];
	}
	
	public String getReadableNumber(){
		return (isNegative ? "-" : "") + SpellUtils.addCommas(this.wholepart) + (hasDecimal && !decimalpart.isEmpty() ? ("." + decimalpart) : "");
	}
}
